import asyncio
import json
import logging
import os
import random
# TODO 涉及数据库操作的 都放到另外一个模块
import sqlite3

import mirai
import requests
from mirai import MessageEvent, Mirai, Face, MessageChain, Image, Plain
from sqlalchemy import create_engine
from sqlalchemy.ext.asyncio import create_async_engine
from sqlalchemy.orm import sessionmaker

from entity import BlogWarehouse, Poetry
from robot_core.preset_content import PresetContent
from robot_service.error_message import ErrorHelper
# TODO 将此类中的方法具体实现迁移 用文件夹分类摆放，并从此类的方法中访问目标方法
from robot_service.message_helper import send_message


class ServiceRepository:

    def __init__(self, bot: Mirai):
        self.__bot = bot
        self.__error_helper = ErrorHelper()
        self.__preset_str = PresetContent()
        self.engine = create_engine("sqlite:///sir_two_spider/SirTwoDB.db")
        # aiosqlite 是异步的sqlite驱动 如果要使用异步模式操作数据库 则需要安装此库并且修改链接字符串
        self.async_engine = create_async_engine("sqlite+aiosqlite:///sir_two_spider/SirTwoDB.db")
        self.session_engine = sessionmaker(bind=self.engine)

    async def blog_search(self, param: str, event: MessageEvent):
        session = self.session_engine()
        session = session.query(BlogWarehouse)
        for p in param.split(','):
            if p.isspace() or p == "":
                continue
            p = p.replace('\\', '')
            session = session.filter(BlogWarehouse.title.like(f'%{p}%'))
        result_list = session.all()
        count = 0
        message_chain = MessageChain()
        for result in result_list:
            if count > 9:
                break
            title = result.title
            url = result.url
            author = result.author
            message_chain.append(f"{count + 1}  >>>  {title} ---{author} \n {url}\n")
            count += 1
        if len(message_chain) < 1:
            message_chain.append("没有搜索到目标博客")
        await send_message(self.__bot, event, message_chain)

    async def sir_two_plz(self, param: str, event: MessageEvent):
        error_message = None
        try:
            sir_two_db = sqlite3.connect('sir_two_spider/SirTwoDB.db')
            sql = 'SELECT title,author,img_url,id,header FROM SirTwoInfo WHERE used = 0 AND sexual = 1 LIMIT 1'
            cu = sir_two_db.cursor()
            cu.execute(sql)
            result = cu.fetchall()[0]

            # TODO 考虑提取requests为单独模块
            import requests
            from requests import adapters
            # 设置最大超时次数
            s = requests.Session()
            s.mount('http://', adapters.HTTPAdapter(max_retries=3))
            s.mount('https://', adapters.HTTPAdapter(max_retries=3))

            img_url = str(result[2])
            header = result[4]
            file_name = str(random.randint(1, 100) + random.randint(2, 200)) + str(random.randint(1, 99))
            file_name_postfix = '.jpg'
            headers = {
                'authority': 'i.pximg.net',
                'cache-control': 'max-age=0',
                'sec-ch-ua': '";Not A Brand";v="99", "Chromium";v="94"',
                'sec-ch-ua-mobile': '?0',
                'sec-ch-ua-platform': '"Linux"',
                'upgrade-insecure-requests': '1',
                'user-agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.71 Safari/537.36',
                'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9',
                'sec-fetch-site': 'cross-site',
                'sec-fetch-mode': 'navigate',
                'sec-fetch-user': '?1',
                'sec-fetch-dest': 'document',
                'referer': 'https://www.pixiv.net/',
                'accept-language': 'en-US,en;q=0.9,zh-CN;q=0.8,zh;q=0.7'
            }

            try:
                res = requests.get(img_url, timeout=(10, 20), headers=headers)
                if res.status_code == 404:
                    # headers['if-modified-since'] = header
                    headers['pragma'] = 'no-cache'
                    headers['cache-control'] = 'no-cache'
                    file_name_postfix = '.png'
                    img_url = img_url.replace('jpg', 'png')
                    res = requests.get(img_url, timeout=(10, 20), headers=headers)
            except Exception as e:
                res = requests.get(img_url, headers=headers)

            with open(file_name + file_name_postfix, 'wb') as f:
                f.write(res.content)
            from pathlib import Path
            message_chain = MessageChain([
                Image(path=f'{file_name + file_name_postfix}'),
                f'标题：{result[0]}，作者：{result[1]}'
            ])
            sql = f'UPDATE SirTwoInfo SET used = 1 WHERE id = {result[3]}'
            cu.execute(sql)
            sir_two_db.commit()
            await send_message(self.__bot, event, message_chain)

        except Exception as e:
            logging.debug(result[0] + ":" + str(e))
            error_message = mirai.MessageChain(['这张太色了 我决定自己看 >>> ', Face(name='呲牙')])
        finally:
            try:
                os.remove(f'{file_name + file_name_postfix}')
            except Exception as e:
                error_message = mirai.MessageChain([f'这张太色了 我决定自己看 >>> {str(e)}', Face(name='呲牙')])
            if error_message is not None:
                await send_message(self.__bot, event, error_message)

    async def life_index(self, param: str, event: MessageEvent):
        api_url = f"https://www.tianqiapi.com/life/lifepro?appid=48271183&appsecret=r6QRzKyh&city={param}"
        try:
            message_chain: mirai.Messagechain
            res = requests.get(api_url)
            if res.status_code != 200:
                message_chain = mirai.MessageChain(['气象局与本小子的连接已断开,请稍候重试(请求失败)', Face(name='呲牙')])
            re = res.content.decode("unicode_escape")
            li_dict = json.loads(re)
            data = li_dict.get("data")
            message_list = list()
            effective_list = ["空调开启指数",
                              "过敏指数",
                              "穿衣指数",
                              "空气污染扩散条件指数",
                              "旅游指数",
                              "中暑指数"]
            for k, v in data.items():
                if v.get("name") in effective_list:
                    message_list.append(mirai.Plain(f"{v.get('name')}>> 等级: {v.get('level')} | 建议: {v.get('desc')}\n"))
            message_chain = mirai.MessageChain(message_list)
        except Exception as e:
            message_chain = mirai.MessageChain([Plain(f"气象局与本小子的连接已断开,请稍候重试({str(e)})")])
        finally:
            await send_message(self.__bot, event, message_chain)

    async def dice_service(self, param: str, event: MessageEvent):
        error_message = None
        try:
            dice_param = param.split('d')
            if len(dice_param) == 2:
                times = 0
                max_dice_value = 0
                try:
                    times = int(dice_param[0])
                    max_dice_value = int(dice_param[1])
                except Exception as e:
                    # noinspection PyTypeChecker
                    error_message = mirai.MessageChain(
                        [str(self.__error_helper.error_msg_dict.get('param_error')) + '>>>' + str(e)])
                    raise e

                try:
                    if times > 1000000:
                        raise Exception("掷骰次数不能超过一百万次")
                    total_value = 0
                    await asyncio.sleep(1)
                    for time in range(1, times + 1):
                        total_value += random.randint(1, max_dice_value)
                    oops_str = random.choice(self.__preset_str.presetStr.get('DiceOops'))
                    name = str(event.sender.get_name())
                    await send_message(self.__bot, event,
                                       mirai.MessageChain([Plain(name + '骰出了' + str(oops_str) + ':' + str(total_value))]))
                except Exception as e:
                    error_message = mirai.MessageChain([Plain('Oops,骰子被狗肉吃掉了，请继续支持避难所科技>>> ' + str(e))])
            else:
                # noinspection PyTypeChecker
                error_message = mirai.MessageChain([
                    str(self.__error_helper.error_msg_dict.get('param_error'))
                ])
        finally:
            if error_message is not None:
                await send_message(self.__bot, event, error_message)

    @staticmethod
    def dice_value(times: int, max_dice_value: int):
        total_value = 0
        for times in range(1, times + 1):
            total_value += random.randint(1, max_dice_value)
        return total_value

    async def bot_shutdown(self, param: str, event: MessageEvent):
        """
        机器人休眠
        :param event:
        :param param: 如果参数为1 则关闭机器人，否则为休眠
        """
        if event.sender.id == 1052700448:
            if param == '1':
                await send_message(self.__bot, event, mirai.MessageChain(['886 爷要下班了', Face(name='呲牙')]))
                await self.__bot.shutdown()
            else:
                await send_message(self.__bot, event, mirai.MessageChain([Plain('PipBoy shutdown>> '), Plain(' Good Bye World')]))
        else:
            return

    async def bot_startUp(self, param: str, event: MessageEvent):
        """
        机器人苏醒
        """
        if event.sender.id == 1052700448:
            await send_message(self.__bot, event, mirai.MessageChain([Plain('>>PipBoy is initialized')]))
        else:
            return

    async def wpf_push(self):
        await self.__bot.send_group_message(340500857, MessageChain([Plain("邀请您加入交流群 [WPFDevelopers.Minimal]\n"),
                                                                     Plain("群号: 458041663 \n公众号: [WPF开发者]\n"),
                                                                     Plain("项目地址: https://github.com/WPFDevelopersOrg\n"),
                                                                     Plain("Gitee: https://gitee.com/WPFDevelopersOrg")]))

    async def dayly_poetry(self):
        group_list = await self.__bot.group_list()
        already_sent = list()
        session = self.session_engine()

        try:
            result = session.query(Poetry).filter(Poetry.been_used == 0).first()
            poetry = MessageChain([Plain("早上好亲爱的朋友们,今天也是充满希望的一天!\n\n"),
                                   Plain(result.content + '\n')])
            source = f"----{result.source}\n" if result.source != "" else ""
            if source != "":
                poetry.append(Plain(source))
            poetry.append(Plain(result.content_source))
            await self.__bot.send_group_message(749396837, poetry)
            for group in group_list.data:
                group_id = group.id
                if group_id not in already_sent:
                    try:
                        await self.__bot.send_group_message(group_id, poetry)
                    except Exception as e:
                        if e.code == 20:
                            already_sent.append(group_id)
                            continue
                        else:
                            raise
                    already_sent.append(group_id)
            result.been_used = 1
        except Exception as e:
            raise e
        finally:
            session.commit()
